const common = require('../../common')
const getDbName = require('../getDbName')
const {getResult, getError} = require('../../handle')

/**
 * 必要性判断
 * data：原始数据
 * required：必要性的字段
 * requiredType：必要性的类型：
 * -1：忽略必要性判断；0：不新增；1：仍然新增（就会导致必要的数据不完整）
 */
const handleRequired = (data, required, requiredType) => {
	return new Promise((resolve, reject) => {
		if (requiredType < 0 || !required || required.length ===  0) {
			// 不用判断必要性
			resolve(data)
		} else {
			// 是否满足必要性
			const bool = (item) => {
				// 获取不满足必要性的字段名称
				const keys = []
				required.map(key => {
					if (!item[key] && item[key] !== 0 && item[key] !== false) {
						// 不满足必要性
						keys.push(key)
					}
				})
				return keys
			}
			
			// 需要判断必要性
			const arr = [], errKeys = []
			data.map(item => {
				const keys = bool(item)
				if (keys.length === 0) {
					arr.push(item)
				} else {
					switch (requiredType){
						case 0: // 不新增
							keys.map(key => {
								if (errKeys.indexOf(key) === -1) {
									errKeys.push(key)
								}
							})
							break
						case 1: // 仍然新增，会导致数据不完整
							arr.push(item)
							break
						default:
							break;
					}
				}
			})
			if (arr.length > 0) {
				resolve(arr)
			} else {
				reject(errKeys)
			}
		}
	})
}

/**
 * 唯一性判断
 * data：原始数据
 * onlyKeys：唯一性的字段。二维数组
 * onlyType：必要性的类型：
 * -1：忽略唯一性判断；0：不新增；1：直接新增；2：修改原数据（只修改本次已有的）；3：覆盖原数据（会保留_id）；4：覆盖原数据（不保留_id）
 */
const handleOnlyKeys = (data, onlyKeys, onlyType, db, name) => {
	return new Promise((resolve, reject) => {
		if (onlyType < 0 || !onlyKeys || onlyKeys.length === 0) {
			// 不用判断唯一性
			resolve({data})
		} else {
			/**
			 * 是否满足唯一性
			 * 
			 * 先对自身的唯一性数据做判断
			 * 保留满足唯一性的数据后再
			 * 逐个数据，逐个唯一性去查询
			 */
			
			// 自身数据先判断
			for (let h = data.length - 1; h >= 0; h--) {
				var bool = true // 是否满足唯一性
				for (let i = 0; i < data.length; i++) {
					if (i === h) {/**相同项不处理*/} else {
						let temp = false // 该数据是否不满足唯一性
						for (let j = 0; j < onlyKeys.length; j++) {
							onlyKeys[j].map(key => { // 综合起来要满足唯一性
								if (data[h][key] !== data[i][key]) { // 只要有这一项满足条件，就说明满足唯一性
									temp = true
								}
							})
							if (temp) {/**该项满足，还得判断其他项*/} else { // 该项不满足，其它的不用判断了。
								bool = false
								break
							}
						}
						if (bool) {/**该数据暂时满足，还得判断其他数据*/} else { // 已明确该数据不满足唯一性，不用再往下遍历
							break
						}
					}
				}
				if (bool) {/**满足唯一性*/} else {
					// 不满足唯一性
					switch (onlyType){
						case 1: // 直接新增。不用处理
							break
						case 0: // 不新增。删除最后一个，最终只保留最前面的项
						case 2: // 修改原数据（只修改本次已有的）。删除最后一个，最终只保留最前面的项
						case 3: // 覆盖原数据（会保留_id）。删除最后一个，最终只保留最前面的项
						case 4: // 覆盖原数据（会保留_id）。删除最后一个，最终只保留最前面的项
						default:
							data.splice(h, 1)
							break
					}
				}
			}
			
			// 再对线上数据判断
			const dbCmd = db.command
			db = db.collection(name)
			// 不满足唯一性的字段集合，满足唯一性的数据集合
			const keys = [], // 不满足唯一性，不新增时提示的字段。同onlyKeys，唯一性字段集合，提示已存在
				  arr = [] // 满足唯一性条件后可以新增的数据
			var hasUpdate // 是否已经执行过修改
			// 逐个数据循环判断
			const cycleItem = (itemIndex = 0) => {
				if (itemIndex < data.length) {
					
					// 请求过程中出错的处理
					var fetchFail = (err) => {
						// 忽略该数据，直接下一个
						cycleItem(itemIndex + 1)
					}
					
					// 该数据是否满足唯一性的条件，以及不满足的处理
					var handle = (res, ids, obj) => {
						if (res === true) {
							// 满足条件，继续下一个
							arr.push(data[itemIndex])
							cycleItem(itemIndex + 1)
						} else {
							switch (onlyType){
								case 0: // 不新增。继续下一个即可
									if (keys.indexOf(res) === -1) {
										keys.push(res)
									}
									cycleItem(itemIndex + 1)
									break
								case 1: // 直接新增
									arr.push(data[itemIndex])
									cycleItem(itemIndex + 1)
									break
								case 2: // 修改原数据（只修改本次已有的）。如果原数据存在多个，则只保留一个，其余删除
									db.doc(ids[0]).updateAndReturn(data[itemIndex]).then(res => {
										if (res.result) {
											res = res.result
										}
										hasUpdate = res.doc
										// 第一个已经修改了
										ids.shift()
										if (ids.length > 0) {
											db.where({_id: dbCmd.in(ids)}).update({remove: true, alert_time: Date.now()}).then(res => {
												// 继续下一个即可
												cycleItem(itemIndex + 1)
											}).catch(fetchFail)
										} else {
											// 继续下一个即可
											cycleItem(itemIndex + 1)
										}
									}).catch(fetchFail)
									break
								case 3: // 覆盖原数据（会保留_id）。删除所有，再新增一个并加入第一个_id
									data[itemIndex]._id = ids[0]
								case 4: // 覆盖原数据（不保留_id）。删除所有，再新增一个
									db.where({_id: dbCmd.in(ids)}).update({remove: true, alert_time: Date.now()}).then(res => {
										// 直接新增
										data[itemIndex].creat_type = onlyType === 3 ? 1 : 2
										arr.push(data[itemIndex])
										cycleItem(itemIndex + 1)
									}).catch(fetchFail)
									break
								default:
									break;
							}
						}
					}
					
					// 逐个唯一性key循环判断
					const cycleKey = (keyIndex = 0) => {
						if (keyIndex < onlyKeys.length) {
							var params = {}
							onlyKeys[keyIndex].map(key => {
								params[key] = data[itemIndex][key]
							})
							// 该参数需加上remove字段
							params.remove = dbCmd.neq(true)
							// 在后端'timestamp desc'的写法提示“排序字符不合法”
							db.where(params).orderBy('timestamp', 'desc').get().then(res => {
								if (res.result) {
									res = res.result
								}
								if (res.data.length === 0) {
									// 满足唯一性，走下一个唯一性key循环
									cycleKey(keyIndex + 1)
								} else {
									// 已经不满足条件了
									const ids = []
									res.data.map(obj => {
										ids.push(obj._id)
									})
									handle(onlyKeys[keyIndex], ids)
								}
							}).catch(fetchFail)
						} else {
							// 唯一性字段判断完了。满足条件，继续 下一个
							handle(true)
						}
					}
					cycleKey(0)
				} else {
					/**
					 * 每个数据都判断完了
					 * data：实际需要新增的数据
					 * errKeys：出现不唯一的字段提示
					 * hasUpdate：是否已经处理了修改了。并且是已经修改过的数据返回
					 */
					resolve({data: arr, errKeys: keys, hasUpdate})
				}
			}
			cycleItem(0)
		}
	})
}

/**
 * 本地新增。一般不建议操作，而且需要数据库开放权限才允许
 * 一定要先查询数据库信息，获取三个数据
 * 1，必要性数据。先判断其必要性是否满足条件
 * 		不满足条件的话，根据设定的类型进行处理
 * 2，唯一性。再判断其唯一性是否满足条件
 * 		不满足条件的话，根据设定的类型进行处理
 * 3，默认值数据。满足条件后，会将默认值赋值，再做新增处理
 * 
 * collection：是否已有固定的操作对象了
 * 如果isReturn位true，返回值是数组；反之为对象
 */
module.exports = ({cloud, space, name, dbGet, collection} = {}, params, config, isApp = false) => {
	return new Promise((resolve, reject) => {
		var {
			data, // 要新增的数据。对象或者对象数组
			isReturn, // 是否返回新增后的数据
			addType // 新增时不满足条件的处理类型
		} = params
		if (name) {
			// 是否返回数组模式
			const isArray = Array.isArray(data)
			// 都转为数组处理
			if (!isArray) {data = [data]}
			if (data.length > 0) {
				var db = cloud.database()
				// 1，查询数据库信息
				dbGet(name, space).then(res => {
					var {required, onlyKeys, defaultValue, properties} = res.data
					const {
						force = false, // 是否强制新增。强制新增是指对已有创建的信息仍然新增，适用于批量修改=批量删除后批量新增。非强制新增，会对创建信息全部清空
						requiredType = 0, // 判断必要性后的类型，-1：忽略必要性判断；0：不新增；1：仍然新增（就会导致必要的数据不完整）
						onlyType = 0 , // 判断唯一性后的类型，-1：忽略唯一性判断；0：不新增；1：修改原数据（只修改本次已有的）；2：覆盖原数据（会保留_id）；3：覆盖原数据（不保留_id）
						// onlyKeys, 自定义的唯一性字段集合。同数据库配置设置，二维数组
						// required, 自定义的必要性字段集合。同数据库配置设置，一维数组
					} = addType || {}
					if (addType && addType.required) {
						required = addType.required
					}
					if (addType && addType.onlyKeys) {
						onlyKeys = addType.onlyKeys
					}
					// 必要性判断
					handleRequired(data, required, requiredType).then(res => {
						// 唯一性判断
						name = getDbName(name, space)
						handleOnlyKeys(res, onlyKeys, onlyType, db, name).then(({data, errKeys, hasUpdate}) =>  {
							const result = {
								message: '新增成功'
							}
							// 处理文本
							const marr = []
							var toast = '', string = ''
							if (data.length > 0) {
								marr.push(`数据库“${name}”新增${data.length}条成功`)
								toast = `新增${data.length}条成功`
							}
							if (hasUpdate) {
								marr.push('数据修改成功')
								toast = `数据修改成功`
							}
							if (errKeys && errKeys.length > 0) {
								// 通过errKeys获取对应的名称
								errKeys.map(keys => {
									const names = []
									keys.map(key => {
										names.push(properties[key].title)
									})
									string += `“${names.join('、')}”已存在；`
								})
								string = string.slice(0, -1)
								marr.push(string)
								toast = string
							}
							if (marr.length > 0) {
								result.message = marr.join('；')
							}
							// 处理数据
							if (data.length > 0) {
								// result.toast = toast
								// 给数据添加固定值和默认值
								data.map(item => {
									if (!force || !item.creator) {
										item.creator = common.necessary.User
									}
									if (!force || !item.timestamp) {
										item.timestamp = common.startTime
									}
									// 前两项一定要有force参数决定，后两项不需要
									if (!item.creat_type && item.creat_type !== 0) {
										item.creat_type = item.creat_type || 0
									}
									if (!item.remove && item.remove !== false) {
										item.remove = false
									}
									defaultValue && Object.keys(defaultValue).forEach(key => {
										if (item[key] || item[key] === false || item[key] === 0 || item[key] === '') {
											// 已经存在就不用赋默认值
										} else {
											item[key] = defaultValue[key]
										}
									})
								}) 
								if (collection) {
									db = collection.add(data[0])
								} else {
									db = db.collection(name).add(data)
								}
								db.then(res => {
									if (res.result) {
										res = res.result
									}
									var {ids, id} = res
									if (!ids) {
										ids = [id]
									}
									if (isReturn)  {
										// 返回值是数组
										const copyid = () => {
											const arr = []
											ids.map((_id, index) => {
												arr.push({
													...data[index], _id
												})
											})
											result.data = arr
										}
										if (1) {
											/**
											 * 直接赋值，有可能数据不一致
											 * 已经过两个数据的测试，发现一致
											 */
											copyid()
											resolve(getResult(result))
										} else {
											// 查询已经新增成功的数据返回
											const dbCmd = uniCloud.database().command
											db.collection(name).where({_id: dbCmd.in(ids)}).get().then(res => {
												result.data = res.data
												resolve(getResult(result))
											}).catch(err => {
												copyid()
												resolve(getResult(result))
											})
										}
									} else {
										// 返回值是对象
										if (ids.length === 1) {
											res.id = ids[0]
										}
										result.data = res
										resolve(getResult(result))
									}
								}).catch(reject)
							} else {
								if (hasUpdate) {
									result.data = hasUpdate
									resolve(getResult(result))
								} else if (errKeys && errKeys.length > 0) {
									reject(getError(string))
								} else {
									reject(getError('没有实际新增项'))
								}
							}
						})
					}).catch(errKeys => {
						if (Array.isArray(errKeys)) {
							// 通过errKeys获取对应的名称
							const names = []
							errKeys.map(key => {
								names.push(properties[key].title)
							})
							reject(getError(names.join('、') + '不存在'))
						} else {
							reject(errKeys)
						}
					})
				}).catch(reject)
			} else {
				reject(getError(`数据库“${name}”没有需要新增的数据`))
			}
		} else { // 该场景已不存在
			reject(getError(`数据库“${name}”没有注册`))
		}
	})
}